<template>
  <div class="lazy-image" :class="{ 'lazy-image--loaded': isLoaded, 'lazy-image--error': isError }">
    <img
      ref="imageRef"
      :data-src="src"
      :alt="alt"
      :class="imageClass"
      @load="handleLoad"
      @error="handleError"
    />
    
    <!-- 加载中占位符 -->
    <div v-if="!isLoaded && !isError" class="lazy-image__placeholder">
      <div class="lazy-image__spinner"></div>
    </div>
    
    <!-- 错误状态 -->
    <div v-if="isError" class="lazy-image__error">
      <ElIcon :size="48">
        <PictureFilled />
      </ElIcon>
      <p>图片加载失败</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { PictureFilled } from '@element-plus/icons-vue'

const props = defineProps({
  // 图片地址
  src: {
    type: String,
    required: true
  },
  // 图片描述
  alt: {
    type: String,
    default: ''
  },
  // 自定义类名
  imageClass: {
    type: String,
    default: ''
  },
  // 根元素边距（提前多少像素开始加载）
  rootMargin: {
    type: String,
    default: '50px'
  }
})

const imageRef = ref(null)
const isLoaded = ref(false)
const isError = ref(false)
let observer = null

// 加载图片
const loadImage = () => {
  const img = imageRef.value
  if (!img) return
  
  const src = img.getAttribute('data-src')
  if (src) {
    img.src = src
  }
}

// 图片加载成功
const handleLoad = () => {
  isLoaded.value = true
}

// 图片加载失败
const handleError = () => {
  isError.value = true
}

onMounted(() => {
  // 检查浏览器是否支持 IntersectionObserver
  if ('IntersectionObserver' in window) {
    observer = new IntersectionObserver(
      (entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            loadImage()
            // 加载后停止观察
            observer.unobserve(entry.target)
          }
        })
      },
      {
        rootMargin: props.rootMargin
      }
    )
    
    if (imageRef.value) {
      observer.observe(imageRef.value)
    }
  } else {
    // 降级方案：直接加载图片
    loadImage()
  }
})

onUnmounted(() => {
  if (observer && imageRef.value) {
    observer.unobserve(imageRef.value)
    observer.disconnect()
  }
})
</script>

<style lang="scss" scoped>
.lazy-image {
  position: relative;
  overflow: hidden;
  background: var(--bg-secondary);
  border-radius: $radius-md;
  
  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity $transition-base $transition-ease;
  }
  
  &--loaded img {
    opacity: 1;
  }
  
  &__placeholder {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    @include flex-center;
    background: var(--bg-tertiary);
  }
  
  &__spinner {
    width: 40px;
    height: 40px;
    border: 3px solid var(--border-color);
    border-top-color: $primary-color;
    border-radius: $radius-full;
    animation: spin 1s linear infinite;
  }
  
  &__error {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    @include flex-center;
    flex-direction: column;
    color: var(--text-tertiary);
    background: var(--bg-tertiary);
    
    p {
      margin-top: $spacing-sm;
      font-size: $font-size-sm;
    }
  }
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
</style>

